/*
  This file is part of SPARK: SharePoint Application Resource Kit.
  The project is distributed via CodePlex: http://www.codeplex.com/spark/
  Copyright (C) 2003-2009 by Thomas Carpe. http://www.ThomasCarpe.com/

  SPARK is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  SPARK is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with SPARK.  If not, see <http://www.gnu.org/licenses/>.
*/

namespace Behemoth.SharePoint.CustomFieldTypes {

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;

    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebControls;

    using Behemoth.Web.UI.WebControls;

	/// <summary>
	/// This class contains code to workaround an issue that prevents the properties
	/// of a custom fieldName from being properly displayed in the FldEditEx.aspx page.
	/// </summary>
	public class CustomFieldPropertyDisplayWorkaround {

		/// <summary>
		/// The caller is responsible for ensuring that this is called only once.
		/// </summary>
		/// <param name="fieldName"></param>
		/// <returns></returns>
		public static object DoHookup( SPField field) {
#if DisableCustomFieldPropertyDisplayWorkaround
			return null;
#endif

			if (HttpContext.Current == null || field == null)
				return null;
			Page page = HttpContext.Current.Handler as Page;
			if (page == null || page.IsPostBack)
				return null;

			// ensure that we only attach a single pre render event for each unique fieldName name
			// TODO do something to ensure that fields trigger by other parts of the form or custom
			// properties do not get added here
			List<string> fieldList = GetFieldList(page);
			if (!fieldList.Contains( field.InternalName )) {
				object work = new CustomFieldPropertyDisplayWorkaround( page, field );
				fieldList.Add( field.InternalName );
				return work;
			}
			return null;
		}

		private static List<string> GetFieldList(Page page) {
			List<string> fieldList = page.Items["FieldList"] as List<string>;
			if (fieldList == null) {
				fieldList = new List<string>();
				page.Items.Add("FieldList", fieldList);
			}
			return fieldList;
		}

		private SPField _field = null;
		private Page _page = null;

		internal CustomFieldPropertyDisplayWorkaround( Page page, SPField field ) {
			this._page = page;
			this._field = field;
			_page.PreRender += new EventHandler( page_PreRender );
		} // SPField fieldName

		protected void page_PreRender( object sender, EventArgs e ) {
			if (_field == null) return;
			if (_page == null || _page.IsPostBack) return;
			ListFieldIterator listIterator = GetListIteratorControl( _page ) as ListFieldIterator;
			ReplaceCorruptedFieldValues( listIterator, this._field );
		}

		private void ReplaceCorruptedFieldValues( ListFieldIterator listIterator, SPField field ) {
			if (listIterator == null)
				return;
			if (listIterator.ControlMode == SPControlMode.New)
				return;
			foreach (Control propertyTemplate in listIterator.Controls) {
				// there is generally always a template for the individual fieldName property
				foreach (Control lic in propertyTemplate.Controls) {
					FormField ff = lic as FormField; // this is the form fieldName for the custom property, not the actual list item fieldName
					if (ff != null) { // filter out any LiteralControls that are floating around the form fieldName
						// get the fieldName name and do the substitution
						string fieldName = ff.FieldName;
						object prop = field.GetCustomProperty( fieldName );
						ff.ItemFieldValue = prop;
						ff.Value = prop; // if this doesn't work we can impact the value directly from the form itself?
					}
				}
			}
		}

		/// <summary>
		/// Search a Page object for the ListIterator control that acts
		/// as a container for all the custom property fieldName controls for
		/// that page. This will only work on SharePoints FldEditEx.aspx page.
		/// </summary>
		/// <param name="page"></param>
		/// <returns></returns>
		private Control GetListIteratorControl( Page page ) {
			/*
			Control phMain = page.Form.FindControl( "PlaceHolderMain" ); if (phMain == null) return;
			Control oSettings = phMain.FindControl( "OptionalSettings" ); if (oSettings == null) return;
			Control phControls = oSettings.FindControl( "PlaceHolderControls" ); if (phControls == null) return;
			Control custom = oSettings.FindControl( "Customization" ); if (custom == null) return null;
			*/
			Control custom = WebControlTools.RecurseFindControl( page.Form, "Customization" );
			if (custom == null)
				return null;
			ListFieldIterator listIterator = WebControlTools.GetChildControlByType( custom, typeof( ListFieldIterator ) ) as ListFieldIterator;
			return listIterator;
		}

	}

}
